package observer;

import java.util.HashMap;
import java.util.Map;

/**
 * 此类为管理类，所有的消息接收者，都应该在此类中做注册动作以及注销动作。
 * 所有的消息传递者，都应该将消息，交给此类的对象来实现，消息传递。
 */
public class Manager {

    /**
     * 保存分块的消息中间者。
     */
    private volatile Map<String, Saver> savers;

    /**
     * 本类全局的唯一对象。
     */
    private static Manager manager = new Manager();

    /**
     * 构造方法，用于初始化参数。
     */
    private Manager() {
        savers = new HashMap<String, Saver>();
    }

    /**
     * 通过此方法，获取本类的唯一对象。
     *
     * @return 本类唯一对象。
     */
    public static Manager getInstance() {
        if (manager == null) {
            manager = new Manager();
        }
        return manager;
    }

    /**
     * 通过此方法，通过flag找出指定的的消息中间者。然后通过此中间者，向接收者传递消息。
     *
     * @param flag        通过此变量，确定消息要传递的区域，如果为null，则表示此次消息，在全局传递。
     * @param transmitter 消息传递者，此对象中，携带者，要被传递的消息。
     */
    public void notifyReceiver(String flag, Transmitter transmitter) {
        if (flag == null) {
            for (Saver saver : this.savers.values()) {
                saver.notifyReceiver(transmitter);
            }
        } else if (this.savers.containsKey(flag)) {
            Saver saver = this.savers.get(flag);
            saver.notifyReceiver(transmitter);
        }
    }

    /**
     * 通过此方法注册消息接收者。
     * flag用于区分，此接收者要接收哪个区域的消息。
     * 使用这种分区域的模式，是为了当程序过于庞大时，不会因为大量的循环，导致程序响应速度大幅降低。
     *
     * @param flag     确定此接收者要注册的消息中间者
     * @param receiver 要注册的消息接收者。
     */
    public void register(String flag, Receiver receiver) {
        Saver saver = null;
        if (this.savers.containsKey(flag)) {
            saver = this.savers.get(flag);
        } else {
            saver = new Saver();
            this.savers.put(flag, saver);
        }
        saver.register(receiver);
    }

    /**
     * 通过此方法，注销指定区域的消息接收者。
     * 具体说明请参照上一条，注册消息接收者方法。
     *
     * @param flag     确定要注销的区域
     * @param receiver 要注销的消息接收者
     */
    public void unregister(String flag, Receiver receiver) {
        Saver saver = null;
        if (this.savers.containsKey(flag)) {
            saver = this.savers.get(flag);
            saver.unregister(receiver);
        }
    }

    /**
     * 此方法供外部提供使用，用于清除掉所有已注册的所有消息中间者。
     * 此方法应作为程序的资源释放方法。
     * 注：此方法使用后，若要再使用Receiver接收消息，消息接收者需要重新注册。
     */
    public void close(String...flags) {
        if (flags.length == 0){
            for (Saver save : this.savers.values()){
                save.close();
            }
            this.savers.clear();
        }
        for (String flag : flags){
            this.savers.get(flag).close();
            this.savers.remove(flag);
        }
    }
}
